#!/usr/bin/python3

import argparse
import datetime
import hashlib
import html
import json
import os
import re
import socket
import time

RESET = "\x1B[0m"
RED = "\x1B[31m"
GREEN = "\x1B[32m"
YELLOW = "\x1B[33m"
BULE = "\x1B[34m"


def get_QuestionAnswer_text(content):
    error_tip = f"{RED}获取内容失败{RESET}"
    if content is not None and "</span>" in content:
        text = re.match(r'<p><span .*">(.*?)<', content)
        if text is not None:
            text = text.group(1)
            text = html.unescape(text)
    elif content is not None and "<p>" in content:
        text = re.match(r'^<p>(.*?)<', content)
        if text is not None:
            text = text.group(1)
            text = html.unescape(text)
    else:
        text = content

    if content is not None and (text is None or len(text) == 0):
        text = error_tip
    return text.strip() if text is not None else text


def mode1(parsed_data, Answer_key):
    question_num = 1
    for item in parsed_data['Result']:
        question_content = get_QuestionAnswer_text(item['Question'])
        if "<img" in item['Question']:
            if question_content[:4] == "（有图）":
                question_content = f"{YELLOW}{question_content[:4]}{RESET}{question_content[4:]}"
            else:
                question_content = f"{YELLOW}（有图）{RESET}{question_content}"
        print(f"{item['AnswerTypeEnumDesc']} {question_num}.{question_content}")
        for key in ['A', 'B', 'C', 'D']:
            if item[Answer_key[key]] is not None and key in item['ShowAnswer']:
                print(f"{GREEN}{key}.{get_QuestionAnswer_text(item[Answer_key[key]])}{RESET}")
            elif item[Answer_key[key]] is not None:
                print(f"{key}.{get_QuestionAnswer_text(item[Answer_key[key]])}")
        print("")
        question_num += 1


def mode2(parsed_data, Answer_key):
    question_num = 1
    for item in parsed_data['Result']:
        question_content = get_QuestionAnswer_text(item['Question'])
        if "<img" in item['Question']:
            if question_content[:4] == "（有图）":
                question_content = f"{YELLOW}{question_content[:4]}{RESET}{question_content[4:]}"
            else:
                question_content = f"{YELLOW}（有图）{RESET}{question_content}"
        print(f"{item['AnswerTypeEnumDesc']} {question_num}.{question_content}")
        for key in ['A', 'B', 'C', 'D']:
            if item[Answer_key[key]] is not None and key in item['ShowAnswer']:
                print(f"{GREEN}{key}.{get_QuestionAnswer_text(item[Answer_key[key]])}{RESET}")
        print("")
        question_num += 1


def mode3(parsed_data, Answer_key):
    question_num = 1
    for item in parsed_data['Result']:
        print(f"{question_num:>2}:{item['ShowAnswer']:6}", end="")
        if question_num % 5 == 0:
            print("")
        question_num += 1
    if (question_num - 1) % 5 == 0:
        print("-" * 42)
    else:
        print("\n" + "-" * 42)

    display_top3_answer(parsed_data, Answer_key)
    print("")


def mode4(parsed_data, Answer_key):
    group_item = 0
    question_num = 1
    start_num = 0
    end_num = 0
    d_question = ""
    status = 0
    print(f'单选题：', end="")
    for item in parsed_data['Result']:
        if "单选题" == item['AnswerTypeEnumDesc']:
            if start_num == 0:
                start_num = question_num
            d_question += f"{item['ShowAnswer']}"
            end_num = question_num
            status = 1
        elif status == 1:
            if group_item != 0 and group_item % 3 == 0:
                group_item = 0
                print("\n" + " " * 8, end="")
            group_item += 1
            answer_num = f"{start_num}-{end_num}"
            print(f"{answer_num:>5}:{d_question:<7}", end="")
            status = 0
            start_num = 0
            d_question = ""
        if question_num % 5 == 0 and status == 1:
            if group_item != 0 and group_item % 3 == 0:
                group_item = 0
                print("\n" + " " * 8, end="")
            group_item += 1
            answer_num = f"{start_num}-{end_num}"
            print(f"{answer_num:>5}:{d_question:<7}", end="")
            status = 0
            start_num = 0
            d_question = ""
        question_num += 1
    if status == 1:
        if group_item != 0 and group_item % 3 == 0:
            print("\n" + " " * 8, end="")
        answer_num = f"{start_num}-{question_num - 1}"
        print(f"{answer_num:>5}:{d_question:<7}", end="")

    group_item = 0
    question_num = 1
    print(f'\n\n多选题：', end="")
    for item in parsed_data['Result']:
        if "多选题" == item['AnswerTypeEnumDesc']:
            if group_item != 0 and group_item % 5 == 0:
                print(f"\n\t", end="")
            print(f"{question_num:>2}:{item['ShowAnswer']}\t", end="")
            group_item += 1
        question_num += 1

    group_item = 0
    question_num = 1
    start_num = 0
    end_num = 0
    p_question = ""
    status = 0
    print(f'\n\n判断题：', end="")
    for item in parsed_data['Result']:
        if "判断题" == item['AnswerTypeEnumDesc']:
            if start_num == 0:
                start_num = question_num
            p_question += item['ShowAnswer']
            end_num = question_num
            status = 1
        elif status == 1:
            if group_item != 0 and group_item % 3 == 0:
                group_item = 0
                print("\n" + " " * 8, end="")
            group_item += 1
            answer_num = f"{start_num}-{end_num}"
            print(f"{answer_num:>5}:{p_question:<7}", end="")
            p_question = ""
            start_num = 0
            status = 0
        if question_num % 5 == 0 and status == 1:
            if group_item != 0 and group_item % 3 == 0:
                group_item = 0
                print("\n" + " " * 8, end="")
            group_item += 1
            answer_num = f"{start_num}-{end_num}"
            print(f"{answer_num:>5}:{p_question:<7}", end="")
            p_question = ""
            start_num = 0
            status = 0
        question_num += 1
    if status == 1:
        if group_item != 0 and group_item % 3 == 0:
            print("\n" + " " * 8, end="")
        answer_num = f"{start_num}-{end_num}"
        print(f"{answer_num:>5}:{p_question:<7}", end="")
    print("\n" + "-" * 45)

    display_top3_answer(parsed_data, Answer_key)
    print("")


def display_top3_answer(json_data, Answer_key):
    question_num = 1
    for item in json_data['Result']:
        print(f"\r{GREEN}题{question_num}: {RESET}", end="")
        for key in ['A', 'B', 'C', 'D']:
            if key in item['ShowAnswer']:
                print(f"{GREEN}{key}.{get_QuestionAnswer_text(item[Answer_key[key]])}{RESET}")
                print(" " * 5, end="")
        if question_num == 3:
            print(f"\r", end="")
            break
        question_num += 1


def display_answer(mode, file_num, is_cls):
    Answer_key = {'A': 'ShowOptionA', 'B': 'ShowOptionB', 'C': 'ShowOptionC', 'D': 'ShowOptionD'}
    Course_list = get_files()["Course_list"]
    if file_num is None:
        fix_file_num = 0
    else:
        fix_file_num = file_num - 1
    if 0 > fix_file_num or fix_file_num >= len(Course_list):
        print(f"{RED}error{RESET}：{fix_file_num + 1} 超出文件索引范围")
        exit(1)
    if mode is None:
        mode = 4
    if mode not in [1, 2, 3, 4]:
        print(f"{RED}error{RESET}：模式错误（{mode}）")
        exit(1)
    if is_cls:
        os.system("clear")
    file_path = Course_list[fix_file_num]["FilePath"]
    file_time = datetime.datetime.fromtimestamp(get_file_timestamp(file_path) / 1000.0).strftime("%Y-%m-%d %H:%M:%S")
    COLOR = YELLOW if Course_list[fix_file_num]["Duplicate"] else GREEN
    test_tag = f"{BULE}* {RESET}" if Course_list[fix_file_num]["IsTest"] else f"{RESET}  "
    print(
        f"文件：{COLOR}{Course_list[fix_file_num]['FileName']}{test_tag}{Course_list[fix_file_num]['CourseNum']}  {file_time}\n")
    answer_json = load_json(file_path)
    if mode == 1:
        mode1(answer_json, Answer_key)
    elif mode == 2:
        mode2(answer_json, Answer_key)
    elif mode == 3:
        mode3(answer_json, Answer_key)
    elif mode == 4:
        mode4(answer_json, Answer_key)


def get_file_timestamp(file_path):
    re_file_timestamp = re.match(r'(^1[67]\d{11})\.(txt|json)', os.path.basename(file_path))
    if re_file_timestamp is not None:
        file_timestamp = int(re_file_timestamp.group(1))
    else:
        file_timestamp = int(os.path.getmtime(file_path) * 1000)
    return file_timestamp


def get_CourseNum(json_data):
    CourseName_dict = {"数字基带信号实验": "实验1", "时域均衡实验": "实验2", "2FSK调制解调实验": "实验3",
                       "2PSK调制解调实验": "实验4", "PCM模拟信号数字化实验": "实验5", "载波时钟提取实验": "实验6",
                       "频带传输系统 综合实验": "实验7", "综合测试1综合测验1": "综合1", "综合测试2综合测验2": "综合2",
                       "综合测试3综合测验3": "综合3", "error": "未知 "}
    get_CourseNum_key = lambda CourseNum_key, dict: next((key for key in dict.keys() if CourseNum_key in key), "error")
    CourseName = json_data["Result"][0]["CourseName"]
    if "通信原理实验 课堂测验-" in CourseName:
        CourseName = CourseName[12:]
    else:
        CourseName = json_data["Result"][0]["CourseExperName"]
    CourseNum_key = get_CourseNum_key(CourseName, CourseName_dict)
    return CourseName_dict[CourseNum_key]


def get_files():
    storage_path_list = ["/storage/emulated/0/HttpCanary/json", "/storage/emulated/0/HttpCanary/download",
                         "/storage/emulated/0/HttpCanary/ty"]
    ty_key = ["ShowAnswer", "ShowOptionA", "ShowOptionB", "ShowOptionC", "ShowOptionD", "AnswerTypeEnumDesc",
              "Question"]
    Course_json = {"MaxFileNameLength": 0, "MaxSerialNumWidth": 0, "Course_list": []}
    md5_list = []
    Duplicate_md5_list = []
    serial_num = 1
    for storage_path in storage_path_list:
        for root, dirs, files in os.walk(storage_path):
            for file in files:
                if file.endswith('.txt') or file.endswith('.json'):
                    file_path = os.path.join(root, file)
                    with open(file_path, "r", encoding="utf-8") as file:
                        content = file.read()
                    if all(key in content for key in ty_key):
                        file_name = os.path.basename(file_path)
                        json_data = load_json(file_path)
                        md5 = hashlib.md5()
                        md5.update(str(json_data).encode('utf-8'))
                        is_test = True if "课堂测验" in json_data["Result"][0]["CourseName"] else False
                        Course = {"FileName": file_name, "FilePath": file_path, "CourseNum": get_CourseNum(json_data),
                                  "IsTest": is_test, "md5": md5.hexdigest(), "Duplicate": False}
                        Course_json["Course_list"].append(Course)
                        serial_num += 1
                        FileNameLength = len(file_name)
                        if FileNameLength > Course_json["MaxFileNameLength"]:
                            Course_json["MaxFileNameLength"] = FileNameLength
                        if md5.hexdigest() not in md5_list:
                            md5_list.append(md5.hexdigest())
                        else:
                            Duplicate_md5_list.append(md5.hexdigest())

    root_path = "/storage/emulated/0/HttpCanary"
    Course_json["MaxSerialNumWidth"] = len(str(serial_num - 1))
    if len(Course_json["Course_list"]) == 0:
        if (not os.path.exists(root_path) and not os.access(root_path, os.R_OK)) or (
                not os.path.exists(root_path) and os.access(root_path, os.R_OK)):
            print(f"{RED}error{RESET} 权限不足或HttpCanary文件夹不存在")
            exit(1)
        elif os.path.exists("/storage/emulated/0/HttpCanary") and not os.access(root_path, os.R_OK):
            print(f"{RED}error{RESET} 权限不足")
            exit(1)
        else:
            print(f"{RED}error：{RESET}未找到json数据文件")
            exit(1)

    for Course in Course_json["Course_list"]:
        if Course["md5"] in Duplicate_md5_list:
            Course["Duplicate"] = True

    # 排序
    Course_json["Course_list"] = sorted(Course_json["Course_list"],
                                        key=lambda Course_list: get_file_timestamp(Course_list["FilePath"]),
                                        reverse=True)
    return Course_json


def load_json(file_path):
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            return json.loads(f.read())
    except:
        print(f"{RED}error{RESET}：无法打开 {os.path.basename(file_path)} 文件")
        exit(1)


def as_command():
    ty_key = ["ShowAnswer", "ShowOptionA", "ShowOptionB", "ShowOptionC", "ShowOptionD", "AnswerTypeEnumDesc",
              "Question"]
    ip_address = socket.gethostbyname("guettx3.gstar-info.com")
    cache_path = f"/storage/emulated/0/Android/data/com.guoshi.httpcanary/cache/{ip_address}"
    os.makedirs(cache_path, exist_ok=True)
    if not os.access(cache_path, os.R_OK):
        print(f"{RED}error{RESET}：权限不足，操作终止")
        exit(1)
    ignore_file_list = []
    os.system(f"rm {cache_path}/*")
    os.system("clear")
    num = 0
    while True:
        print(f"\r正在扫描中(终止：Ctrl+C)" + "." * num + " " * (3 - num), end="")
        num += 1
        if num >= 4:
            num = 0
        for root, dirs, files in os.walk(cache_path):
            for file in files:
                file_path = os.path.join(root, file)
                if file_path not in ignore_file_list:
                    try:
                        file = open(file_path, "r", encoding="utf-8")
                        content = file.read()
                        file.close()
                        if all(key in content for key in ty_key):
                            json_data = re.search(r'({"Success".*]})', content).group()
                            timestamp = int(time.time() * 1000)
                            os.makedirs("/storage/emulated/0/HttpCanary/ty", exist_ok=True)
                            with open(f"/storage/emulated/0/HttpCanary/ty/{timestamp}.json", "w",
                                      encoding="utf-8") as f:
                                f.write(json_data)
                            return
                        else:
                            ignore_file_list.append(file_path)
                    except:
                        ignore_file_list.append(file_path)
        time.sleep(1)


def ls_command():
    Course_json = get_files()
    serial_num = 1
    for Course in Course_json["Course_list"]:
        file_time = datetime.datetime.fromtimestamp(get_file_timestamp(Course["FilePath"]) / 1000.0).strftime(
            "%Y-%m-%d %H:%M:%S")
        COLOR = YELLOW if Course["Duplicate"] else GREEN
        if Course['IsTest']:
            file_name = f"{COLOR}{Course['FileName']}{BULE}*{RESET}"
            new_file_name_length = len(file_name)
        else:
            file_name = f"{COLOR}{Course['FileName']}{RESET}"
            new_file_name_length = len(file_name) + 1
        file_name_length = Course_json["MaxFileNameLength"] + new_file_name_length - len(Course["FileName"])
        print(
            f"{serial_num:>{Course_json['MaxSerialNumWidth']}}.{file_name:<{file_name_length}} {Course['CourseNum']}  {file_time}")
        serial_num += 1


def del_command(file_index):
    Course_list = get_files()["Course_list"]
    if len(file_index) > 0:
        user_confirm = input(f"是否删除选中的json数据文件[Y/n]")
        if user_confirm == "y" or user_confirm == "Y":
            for file_num in file_index:
                fix_file_num = file_num - 1
                if 0 > fix_file_num or fix_file_num >= len(Course_list):
                    print(f"{RED}error{RESET}：{fix_file_num + 1} 超出文件索引范围")
                    continue
                file_path = Course_list[fix_file_num]["FilePath"]
                try:
                    os.remove(file_path)
                except:
                    print(f"{RED}error{RESET}：{os.path.basename(file_path)} 删除失败")
    else:
        user_confirm = input(f"是否删除全部json数据文件？[Y/n]")
        if user_confirm == "y" or user_confirm == "Y":
            for Course in Course_list:
                try:
                    os.remove(Course["FilePath"])
                except:
                    print(f"{RED}error{RESET}：{Course['FileName']} 删除失败")


def get_terminal_size():
    try:
        columns, rows = os.get_terminal_size(0)
    except OSError:
        # 如果无法获取终端大小，则提供默认值
        columns, rows = 45, 24
    return columns, rows


parser = argparse.ArgumentParser(description='子命令与参数帮助')
# 添加有选项参数
parser.add_argument('-m', type=int, help='选择输出模式，有4种输出模式')
# 添加无选项参数
parser.add_argument('subcommand', nargs='?', type=str, help='子命令，可为这些值：file_index ls as rm del')
parser.add_argument('index', nargs='*', type=int, help='索引，如根据序号索引文件')

args = parser.parse_args()  # 解析有选项参数
subcommand = args.subcommand  # 解析无选项参数
index = args.index  # 解析无选项参数

if subcommand == 'ls':
    ls_command()
elif subcommand == 'as':
    try:
        as_command()
        if args.m is None:
            columns, rows = get_terminal_size()
            display_answer(2, 1, True)
            print(f"{YELLOW}" + "=" * columns + f"{RESET}")
            display_answer(3, 1, False)
        else:
            display_answer(args.m, 1, True)
    except KeyboardInterrupt:
        print(f"\n扫描终止")
elif subcommand is not None and subcommand.isdigit():
    if args.m is None:
        columns, rows = get_terminal_size()
        display_answer(2, int(subcommand), True)
        print(f"{YELLOW}" + "=" * columns + f"{RESET}")
        display_answer(3, int(subcommand), False)
    else:
        display_answer(args.m, int(subcommand), True)
elif subcommand == 'del' or subcommand == "rm":
    del_command(index)
elif subcommand is None:
    display_answer(args.m, 1, True)
else:
    print(f"{RED}error{RESET}：未知的子命令 {subcommand}")
